#include "precompiled.h"

namespace IcyCrystal {
	Symbol* Parser::createFunctionDeclaration(string* functionName, Type* returnType, SymbolList* paramList ){
		Symbol* sym = new Symbol;
		sym->symbolName = *functionName;
		sym->scope = SCOPE_GLOBAL;
		sym->type = *returnType;
		sym->level = 1;
		sym->consts.function.paramDeclaration = paramList;
		/* Create the function namespace */
		sym->consts.function.functionNamespace = new Namespace;
		sym->consts.function.functionNamespace->level = 1;
		sym->consts.function.functionNamespace->scope = SCOPE_LOCAL;
		sym->consts.function.functionNamespace->up = &globalNamespace;
		/* Add the parameters to the namespace */
		SymbolList::iterator it;
		for( it = paramList->begin(); it!= paramList->end(); it++ ){
			Symbol* s = *it;
			sym->consts.function.functionNamespace->SymbolMap[s->symbolName] = s;
		}

		globalNamespace.FunctionMap[sym->symbolName] = sym;
		return sym;
	}	

	bool Parser::functionIsDefined(string& functionName ){
		if( globalNamespace.FunctionMap.count(functionName) > 0)
			return true;
		else
			return false;
	}
	SyntaxTreeList* Parser::getArgumentList(Namespace* currentNamespace, TokenType terminatingToken){
		SyntaxTreeList* ret = new SyntaxTreeList;
		SyntaxTree* next;
		Token* k = lexer.getReadAheadToken();
		while( k->tokenType != terminatingToken ){
			next = getNextExpression(currentNamespace);
			ret->push_back(next);

			k = lexer.getReadAheadToken();
			if( TIS_COMMA(k) ){
				lexer.getNextToken();
				k = lexer.getReadAheadToken();
			}
			else if ( k->tokenType == terminatingToken ){
				lexer.getNextToken();
				break;
			}
		}

		return ret;
	}

	void Parser::verifyArgumentDeclList(SymbolList* argList, bool isDecl){
		map<string, bool> symbols;

		SymbolList::iterator it;
		
		for( it = argList->begin(); it != argList->end(); it++ ){
			Symbol* sym = *it;
			if( !isDecl ){
				if( sym->symbolName.empty() ){
					throw SymbolException("", "Argument must have a name", lexer.fileReader.getCurrentLine());
				}
			}
			if( symbols.count(sym->symbolName) == 0 ){
				// add it.
				symbols[sym->symbolName] = true;
			}
			else {
				throw SymbolException(sym->symbolName, "already defined in function declaration", lexer.fileReader.getCurrentLine());
			}
		}
	}

	SymbolList* Parser::getArgumentDeclList(Namespace* currentNamespace){
		SymbolList* ret = new SymbolList;

		SyntaxTree* next;
		Token* k = lexer.getReadAheadToken();
		while( ! TIS_RPARA(k) ){
			// Get the type specifier.
			//k = lexer.getNextToken();
			Type* paraType = getTypeSpecifier(lexer.getNextToken(), NULL);

			// Is it type only, or type + symbolName?
			k = lexer.getReadAheadToken();
			if(TIS_COMMA(k) || TIS_RPARA(k)){
				// Type only, create fake symbol.
				Symbol* sym = new Symbol;
				sym->scope = SCOPE_UNNAMED_PARA;
				sym->symbolName = "";
				sym->type = *paraType;
				delete paraType;

				ret->push_back(sym);

				if( TIS_RPARA(k)){
					lexer.getNextToken();
					break;
				}

				lexer.getNextToken();
				k = lexer.getReadAheadToken();
			}
			else if( TIS_KEYWORD(k)) {
				// Its a named symbol.
				k = lexer.getNextToken();
				Symbol* sym = new Symbol;
				sym->scope = SCOPE_NAMED_PARA;
				sym->symbolName = *k->value.stringValue;
				sym->type = *paraType;
				delete paraType;

				ret->push_back(sym);
				k = lexer.getReadAheadToken();
				if( TIS_COMMA(k) ){
					lexer.getNextToken();
					k = lexer.getReadAheadToken();
				}
			}
			else {
				throw ParserException("TOKEN_COMMA, TOKEN_RPARA, or TOKEN_KEYWORD", k->tokenTypeToString());
			}

			if ( TIS_RPARA(k)){
				lexer.getNextToken();
				break;
			}
		}

		return ret;
	}
	
}
